package com.javabasic.thread.future;

import com.google.common.collect.Lists;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListenableFutureTask;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.ListeningScheduledExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.javabasic.task_out.course_management_system.Student;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author xiongmin
 * @version 1.0
 * @since Created by work on 2021-08-01 12:38
 */
public class ListenableFutureMethodTest {

    private static ScheduledThreadPoolExecutor scheduledThreadPoolExecutor =  new ScheduledThreadPoolExecutor(2,
            new ThreadFactoryBuilder().setNameFormat("PyEnv-schedule-%d").build(), new ThreadPoolExecutor.DiscardPolicy());
    public static ListeningScheduledExecutorService mExecutorService = MoreExecutors.listeningDecorator(scheduledThreadPoolExecutor);

    public static void main(String[] args) {
        ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(100);
        // 自定义线程池
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(9, 20, 60, TimeUnit.SECONDS, queue);
        ListeningExecutorService listeningExecutor = MoreExecutors.listeningDecorator(threadPoolExecutor);

        MyTask myTask1 = new MyTask("1");
        MyTask myTask2 = new MyTask("2");
        MyTask myTask3 = new MyTask("3");
        MyTask myTask4 = new MyTask("4");


        ListenableFuture<Student> submit1 = listeningExecutor.submit(myTask1);
        ListenableFuture<Student> submit2 = listeningExecutor.submit(myTask2);
        ListenableFuture<Student> submit3 = listeningExecutor.submit(myTask3);
        ListenableFuture<Student> submit4 = listeningExecutor.submit(myTask4);

        // 设置每一个Future的超时时间
        ListenableFuture<Student> studentListenableFuture1 = Futures.withTimeout(submit1, 11, TimeUnit.SECONDS, mExecutorService);
        ListenableFuture<Student> studentListenableFuture2 = Futures.withTimeout(submit2, 5, TimeUnit.SECONDS, mExecutorService);
        ListenableFuture<Student> studentListenableFuture3 = Futures.withTimeout(submit3, 11, TimeUnit.SECONDS, mExecutorService);
        ListenableFuture<Student> studentListenableFuture4 = Futures.withTimeout(submit4, 5, TimeUnit.SECONDS, mExecutorService);



//        ListenableFutureTask<Student> listenableFutureTask1 = ListenableFutureTask.create(myTask1);
//        ListenableFutureTask<Student> listenableFutureTask2 = ListenableFutureTask.create(myTask2);
//        ListenableFutureTask<Student> listenableFutureTask3 = ListenableFutureTask.create(myTask3);
//        ListenableFutureTask<Student> listenableFutureTask4 = ListenableFutureTask.create(myTask4);
//        ListenableFuture<Student> studentTaskListenableFuture1 = Futures.withTimeout(listenableFutureTask1, 10, TimeUnit.SECONDS, mExecutorService);
//        ListenableFuture<Student> studentTaskListenableFuture2 = Futures.withTimeout(listenableFutureTask2, 10, TimeUnit.SECONDS, mExecutorService);
//        ListenableFuture<Student> studentTaskListenableFuture3 = Futures.withTimeout(listenableFutureTask3, 10, TimeUnit.SECONDS, mExecutorService);
//        ListenableFuture<Student> studentTaskListenableFuture4 = Futures.withTimeout(listenableFutureTask4, 10, TimeUnit.SECONDS, mExecutorService);


//        ListenableFuture<?> submitTask1 = listeningExecutor.submit(listenableFutureTask1);
//        ListenableFuture<?> submitTask2 = listeningExecutor.submit(listenableFutureTask2);
//        ListenableFuture<?> submitTask3 = listeningExecutor.submit(listenableFutureTask3);
//        ListenableFuture<?> submitTask4 = listeningExecutor.submit(listenableFutureTask4);
//        ListenableFuture<?> studentListenableFutureTask1 = Futures.withTimeout(submitTask1, 11, TimeUnit.SECONDS, mExecutorService);
//        ListenableFuture<?> studentListenableFutureTask2 = Futures.withTimeout(submitTask2, 5, TimeUnit.SECONDS, mExecutorService);
//        ListenableFuture<?> studentListenableFutureTask3 = Futures.withTimeout(submitTask3, 11, TimeUnit.SECONDS, mExecutorService);
//        ListenableFuture<?> studentListenableFutureTask4 = Futures.withTimeout(submitTask4, 5, TimeUnit.SECONDS, mExecutorService);





//        listenableFutures.add(listenableFutureTask1);
//        listenableFutures.add(listenableFutureTask2);
//        listenableFutures.add(listenableFutureTask3);
//        listenableFutures.add(listenableFutureTask4);

        List<ListenableFuture<Student>> arrayList = Lists.newArrayList();
        arrayList.add(submit1);
        arrayList.add(submit2);
        arrayList.add(submit3);
        arrayList.add(submit4);
//
//        List<ListenableFuture<Student>> arrayList2 = Lists.newArrayList();
//        arrayList2.add(studentListenableFuture1);
//        arrayList2.add(studentListenableFuture2);
//        arrayList2.add(studentListenableFuture3);
//        arrayList2.add(studentListenableFuture4);

//        List<ListenableFuture<Student>> arrayList3 = Lists.newArrayList();
//        arrayList3.add(studentTaskListenableFuture1);
//        arrayList3.add(studentTaskListenableFuture2);
//        arrayList3.add(studentTaskListenableFuture3);
//        arrayList3.add(studentTaskListenableFuture4);

//        List<ListenableFuture<?>> arrayList4 = Lists.newArrayList();
//        arrayList4.add(studentListenableFutureTask1);
//        arrayList4.add(studentListenableFutureTask2);
//        arrayList4.add(studentListenableFutureTask3);
//        arrayList4.add(studentListenableFutureTask4);

//        ListenableFuture<List<Student>> listListenableFuture = Futures.successfulAsList(submit1,submit3,submit2,submit4);
        ListenableFuture<List<Student>> listListenableFuture = Futures.successfulAsList(arrayList);
//        ListenableFuture<List<Student>> listListenableFuture2 = Futures.successfulAsList(arrayList2);
//        ListenableFuture<List<Student>> listListenableFuture3 = Futures.successfulAsList(arrayList3);
//        ListenableFuture<List<Object>> listListenableFuture4 = Futures.successfulAsList(arrayList4);
//        ListenableFuture<List<Student>> listListenableFuture1 = Futures.withTimeout(listListenableFuture, 9, TimeUnit.SECONDS, mExecutorService);
        FutureCallback<List<Student>> futureCallback = new FutureCallback<List<Student>>() {
            @Override
            public void onSuccess(List<Student> result) {
                System.out.println("==========begin=============");
                for (Student student : result) {
                    System.out.println(student +  " -- "+Thread.currentThread().getName());
                }
                System.out.println("==========end=============");
                listeningExecutor.shutdownNow();
                mExecutorService.shutdownNow();
            }
            @Override
            public void onFailure(Throwable t) {
                System.out.println("出错,业务回滚或补偿:" + Thread.currentThread().getName());
                System.out.println(t.getMessage());
                System.out.println(t.getCause());
            }
        };

        FutureCallback<List<Object>> futureCallback2 = new FutureCallback<List<Object>>() {
            @Override
            public void onSuccess(List<Object> result) {
                System.out.println("==========begin2============="+  " -- "+Thread.currentThread().getName());
                for (Object student : result) {
                    System.out.println(student+  " -- "+Thread.currentThread().getName());
                }
                System.out.println("==========end2=============");
//                listeningExecutor.shutdownNow();
            }
            @Override
            public void onFailure(Throwable t) {
                System.out.println("出错,业务回滚或补偿:" + Thread.currentThread().getName());
                System.out.println(t.getMessage());
                System.out.println(t.getCause());
            }
        };

        Futures.addCallback(listListenableFuture,futureCallback,listeningExecutor);
//        Futures.addCallback(listListenableFuture2,futureCallback,listeningExecutor);
//        Futures.addCallback(listListenableFuture1,futureCallback,listeningExecutor);
//        Futures.addCallback(listListenableFuture3,futureCallback,listeningExecutor);
//        Futures.addCallback(listListenableFuture4,futureCallback2,listeningExecutor);


    }
}

/**
 * 线程参数，page,size,请求url,token
 * 超时时间，返回对象(JSONObject)call方法的具体实现可以多样
 */


class MyTask implements Callable<Student> {

    private Student student;

    public MyTask(String id) {
        student = new Student(id);
    }

    @Override
    public Student call() throws Exception {
        System.out.println(Thread.currentThread().getName());
        Thread.sleep(8000);
        System.out.println(Thread.currentThread().getName() + "--" + student);
        return student;
    }
}
